part of '../flutter_ns_ble.dart';


class BlePacket {
  CMD cmd;
  int length;
  int sum;
  List<int> data;

  BlePacket({
    required this.cmd,
    required this.length,
    required this.sum,
    required this.data,
  });

  factory BlePacket.fromBytes(List<int> raw) {
    if (raw.length >= 6) {
      if (raw[0] == CMD.magicCode.value) {
        var cmd = CMD.values.firstOrNullWhere(
          (element) => element.value == raw[1],
        );
        if (cmd != null) {
          var data = raw.sublist(6);
          var dataLength = data.length;
          var length = Uint8List.fromList(
            raw.sublist(2, 4),
          ).buffer.asByteData().getUint16(0, Endian.little);
          var dataSum = 0;
          dataSum = data.sum();
          var sum = Uint8List.fromList(
            raw.sublist(4, 6),
          ).buffer.asByteData().getUint16(0, Endian.little);
          if (dataLength == length) {
            if (dataSum == sum) {
              return BlePacket(cmd: cmd, length: length, sum: sum, data: data);
            } else {
              throw FormatException(
                "数据校验错误, 期望:${raw.sublist(4, 6).toHex()},$sum 实际:$dataSum",
              );
            }
          } else {
            throw FormatException(
              "数据长度错误, 期望:$length 实际:$dataLength,bytes:${raw.toHex(separator: "_")}, data:${data.toHex(separator: "_")}",
            );
          }
        }
        throw UnsupportedError(
          "指令错误, 没有这个指令:${raw[1].toRadixString(16).padLeft(2, '0')}",
        );
      } else {
        throw UnsupportedError("第一个字节必须是0xBC,${raw.toHex(separator: "_")}");
      }
    }
    throw IndexError.withLength(6, raw.length);
  }

  factory BlePacket.fromCmd({required CMD cmd, List<int>? data}) {
    int length = data?.length ?? 0;
    int sum = 0;
    data?.forEach((element) {
      sum += element;
    });
    return BlePacket(
      cmd: cmd,
      length: length,
      sum: sum,
      data: data != null ? Uint8List.fromList(data) : Uint8List(0),
    );
  }

  Uint8List toRaw() {
    List<int> list = List.empty(growable: true);
    list.add(CMD.magicCode.value);
    list.add(cmd.value);
    list.addAll(length.toUint16());
    list.addAll(sum.toUint16());
    list.addAll(data);
    // print(
    //     "packet toBytes:${list.map((e) => e.toRadixString(16).padLeft(2, '0')).joinToString(separator: "_")}");
    Uint8List bytes = Uint8List.fromList(list);
    return bytes;
  }

  @override
  String toString() {
    return "BlePacket{cmd: ${CMD.values.firstOrNullWhere((element) => element.value == cmd)}, length: $length, sum: $sum, data: ${data.toHex(separator: "_")}}";
  }
}

enum PeripheralType{
  gg,
  a1,
  b1,
  f1;
  static PeripheralType fromString(String value) {
    if (value.startsWith("KY_A1") || value.startsWith("A1_")){
      return PeripheralType.a1;
    }else if (value.startsWith("KY_B1") || value.startsWith("B1_")){
      return PeripheralType.b1;
    }else if (value.startsWith("KY_F1") || value.startsWith("F1_")){
      return PeripheralType.f1;
    }else{
      return PeripheralType.gg;
    }
  }
}

class PeripheralInfo {
  final String hardwareVersion;
  final String firmwareVersion;
  final int? battery;

  PeripheralInfo({
    this.hardwareVersion = "",
    this.firmwareVersion = "",
    this.battery,
  });

  @override
  String toString() {
    return "PeripheralInfo(hardwareVersion: $hardwareVersion, firmwareVersion: $firmwareVersion, battery: $battery)";
  }

  factory PeripheralInfo.fromByteArray(Uint8List byteArray) {
    var battery = byteArray[0];
    var hardwareLength = byteArray[1];
    var hardware = String.fromCharCodes(
      byteArray.sublist(2, 2 + hardwareLength),
    );
    var firmwareLength = byteArray[2 + hardwareLength];
    var firmware = String.fromCharCodes(
      byteArray.sublist(
        2 + hardwareLength + 1,
        2 + hardwareLength + 1 + firmwareLength,
      ),
    );
    return PeripheralInfo(
      battery: battery,
      firmwareVersion: firmware,
      hardwareVersion: hardware,
    );
  }
}

enum AskCode {
  success(0x00, "操作成功"),
  dataSizeError(0x01, "数据大小错误"),
  contentError(0x02, "数据内容错误"),
  cmdError(0x03, "指令状态不符"),
  cmdContentError(0x04, "指令格式错误"),
  deviceError(0x05, "设备内部错误"),
  lowBattery(0x06, "设备电量过低"),
  unKnow(0xA0, "未知错误"),
  waiting(0xB0, "还在等消息回来");

  final int byte;
  final String msg;

  const AskCode(this.byte, this.msg);

  static AskCode fromByteArray(Uint8List byteArray) {
    for (var element in AskCode.values) {
      if (element.byte == byteArray.first) {
        return element;
      }
    }
    return AskCode.unKnow;
  }
}

/// 动态设备状态
enum B1DeviceState {
  disable,
  enable,
  idle,
  meas,
  charging;

  static B1DeviceState fromByteArray(Uint8List data) {
    switch (data.first) {
      case 0:
        return B1DeviceState.disable;
      case 1:
        return B1DeviceState.enable;
      case 2:
        return B1DeviceState.idle;
      case 3:
        return B1DeviceState.meas;
      case 4:
        return B1DeviceState.disable;
      case 5:
        return B1DeviceState.charging;
      default:
        throw UnsupportedError(
          "DynamicDeviceState.fromPacket 返回值错误:${data.first}",
        );
    }
  }
}

class EcgData<T> {
  final int order;
  final T data;

  EcgData({required this.order, required this.data});
}

class F1LeadState {
  final bool p1;
  final bool p2;
  final bool p3;
  final bool p4;
  final bool n4;
  final bool com;
  final bool pld;

  F1LeadState({
    this.p1 = false,
    this.p2 = false,
    this.p3 = false,
    this.p4 = false,
    this.n4 = false,
    this.com = false,
    this.pld = false,
  });

  /// [data] 业务数据
  factory F1LeadState.fromBlePacket(Uint8List data) {

    if (data.length < 7){
      return F1LeadState();
    }
    
    return F1LeadState(
      p1: data[6] == 1,
      p2: data[5] == 1,
      p3: data[4] == 1,
      p4: data[2] == 1,
      n4: data[1] == 1,
      com:data[3] == 1,
      pld:data[0] == 1,
    );
  }

  F1LeadState copyWith({
    bool? p1,
    bool? p2,
    bool? p3,
    bool? p4,
    bool? n4,
    bool? com,
    bool? pld,
  }) {
    return F1LeadState(
      p1: p1 ?? this.p1,
      p2: p2 ?? this.p2,
      p3: p3 ?? this.p3,
      p4: p4 ?? this.p4,
      n4: n4 ?? this.n4,
      com: com ?? this.com,
      pld: pld ?? this.pld,
    );
  }

  bool get isLeaded => p1 && p2 && p3 && p4 && n4 && com && pld;

  @override toString() {
    return "F1LeadState(p1: $p1, p2: $p2, p3: $p3, p4: $p4, n4: $n4, com: $com, pld: $pld)";
  }
}
